home *** CD-ROM | disk | FTP | other *** search
- # Source Generated with Decompyle++
- # File: in.pyo (Python 2.5)
-
- from __future__ import with_statement
- import re
- import time
- import urllib2
- import cookielib
- import threading
- from threading import Lock
- from urllib import urlencode
- from datetime import datetime
- from traceback import print_exc
- from util.net import UrlQuery, GetDefaultHandlers, WebFormData
- from util import threaded, scrape_clean, traceguard, EmailAddress, Storage
- from mail import Email
- from common import pref
- from common.emailaccount import EmailAccount
- from logging import getLogger
- log = getLogger('gmail')
- info = log.info
-
- class Gmail(EmailAccount):
- protocol = 'gmail'
- baseAuthUrl = 'https://www.google.com'
- authUrl = '/accounts/ClientLogin'
- tokenUrl = '/accounts/IssueAuthToken'
- messageIdMatcher = re.compile('message_id=([a-z0-9]+?)&')
- jsredirectMatcher = re.compile('location\\.replace\\("(.*)"\\)')
- default_domain = 'gmail.com'
-
- def __init__(self, **k):
- EmailAccount.__init__(self, **k)
- self.token = ''
- self.token_lock = threading.RLock()
- self.datatoken = ''
- self.updated_emails = None
- self.updated_count = None
- self.update_lock = Lock()
- self.emailaddress = EmailAddress(self.name, 'gmail.com')
- if self.emailaddress.domain in ('gmail.com', 'googlemail.com'):
- self.baseMailUrl = '://mail.google.com/mail/'
- else:
- self.baseMailUrl = '://mail.google.com/a/' + self.emailaddress.domain + '/'
- self.browser_http = 'https'
- self.init_jar()
-
- can_has_preview = True
-
- def _reset_state(self):
- self.init_jar()
- self.token = self.datatoken = ''
- self.sid = None
- self.lsid = None
-
-
- def browserBaseMailUrl(self):
- return self.browser_http + self.baseMailUrl
-
- browserBaseMailUrl = property(browserBaseMailUrl)
-
- def internalBaseMailUrl(self):
- return 'https' + self.baseMailUrl
-
- internalBaseMailUrl = property(internalBaseMailUrl)
-
- def init_jar(self):
- self.jar = cookielib.CookieJar()
- self.http_opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(self.jar), *GetDefaultHandlers())
- self.http_opener.addheaders = [
- ('Content-type', 'application/x-www-form-urlencoded'),
- ('Cache-Control', 'no-cache')]
-
-
- def url_token(self):
- if self.web_login and self.token:
- return dict(auth = self.token)
- else:
- return { }
-
- url_token = property(url_token)
-
- def inbox_url(self):
- self.new_token()
- return UrlQuery(self.browserBaseMailUrl, search = 'inbox', **self.url_token)
-
- inbox_url = property(inbox_url)
-
- def urlForEmail(self, email):
- self.new_token()
- return UrlQuery(self.browserBaseMailUrl, fs = '1', tf = '1', view = 'cv', search = 'all', th = str(email.id), **self.url_token)
-
-
- def markAsRead(self, email):
- EmailAccount.markAsRead(self, email)
- self._do_action('read', email)
-
-
- def archive(self, email):
- EmailAccount.archive(self, email)
- self._do_action('archive', email)
- if pref('gmail.markive', False):
- self.markAsRead(email)
-
-
-
- def delete(self, email):
- EmailAccount.delete(self, email)
- self._do_action('delete', email)
-
-
- def reportSpam(self, email):
- EmailAccount.reportSpam(self, email)
- self._do_action('spam', email)
-
-
- def _do_action(self, action, email):
-
- try:
- self.gmail_at
- except KeyError:
- self.new_token(True)
-
- (url, params) = self._actionUrl(action, email.id)
- response = self.webrequest(url, **params)
- log.debug_s('Action %r result: %r', action, response)
-
- _do_action = threaded(_do_action)
-
- def compose(self, to = '', subject = '', body = '', cc = '', bcc = ''):
- extra = dict(fs = '1', view = 'cm')
- su = subject
- for name in 'to su body cc bcc'.split():
- if vars()[name]:
- extra[name] = vars()[name]
- continue
-
- self.new_token()
- extra.update(self.url_token)
- return UrlQuery(self.browserBaseMailUrl, **extra)
-
-
- def _actionUrl(self, action, message_id):
- action_names = dict(archive = 'rc_^i', delete = 'tr', read = 'rd', spam = 'sp')
- if action not in action_names.values():
- action = action_names[action]
-
- url = UrlQuery(self.internalBaseMailUrl, ik = '', search = 'all', view = 'tl', start = '0')
- params = dict(act = action, at = self.gmail_at, vp = '', msq = '', ba = 'false', t = message_id, fs = '1')
- return (url, params)
-
-
- def send_email(self, to = '', subject = '', body = '', cc = '', bcc = ''):
- log.info('sending a mail')
- data = dict(nvp_bu_send = 'Send')
- for name in 'to subject body cc bcc'.split():
- if vars()[name]:
- data[name] = vars()[name].encode('utf-8')
- continue
-
- if not hasattr(self, 'sendpath'):
- response = self.http_opener.open(self.internalBaseMailUrl + '?ui=html')
- urlparse = urlparse
- import urllib2
- respurl = urlparse.urlparse(response.geturl())
-
- try:
- response.close()
- except:
- pass
-
- del response
- self.sendpath = respurl.path
-
- url = 'https://mail.google.com' + self.sendpath
-
- try:
- at = self.gmail_at
- except KeyError:
- at = ''
-
- params = dict(at = at, v = 'b', pv = 'tl', s = 's', fv = 'b', cpt = 'c', cs = 'c')
- if not self.hosted:
- params.update(fv = 'b', cpt = 'c', cs = 'c')
- else:
- params.update(cs = 'b', s = 's')
- url = UrlQuery(url, params)
- response = self.webrequest(url, follow_js_redirects = True, **data)
- log.info('sent a mail')
- log.info('send mail success: %r', bool('Your message has been sent.' in response))
- return True
-
- send_email = threaded(send_email)
-
- def _get_notifier_data(self):
- return self.webrequest(url = UrlQuery(self.internalBaseMailUrl, ui = 'pb'), data = WebFormData(auth = self.datatoken))
-
-
- def hosted(self):
- domain = self.emailaddress.domain
- return None if domain != 'gmail.com' else None
-
- hosted = property(hosted)
-
- def authenticate(self, task = None):
-
- try:
- password = self._decryptedpw()
- data = self.webrequest(self.baseAuthUrl + self.authUrl, data = WebFormData(Email = self.name, Passwd = password, accountType = 'HOSTED_OR_GOOGLE', service = 'mail'))
- except (urllib2.HTTPError, urllib2.URLError):
- e = None
- if e.code == 403:
- log.warning('Invalid username or password')
- self.bad_pw(task)
- return False
- else:
- log.warning('cannot authenticate gmail %s', self.name)
- log.warning('data %s' % e.fp.read())
- raise
- except:
- e.code == 403
-
- if not data:
- log.warning('No data from webrequest')
- raise AssertionError('No data from webrequest')
-
- if data.find('Error=badauth') != -1:
- log.warning('Invalid username or password')
- self.bad_pw(task)
- return False
- else:
- log.debug('received token data: %r', data)
- (sid, lsid, token) = data.split('\n')[:3]
- self.sid = sid
- self.lsid = lsid
- self.datatoken = token.split('=')[1]
- d = dict([
- sid.split('='),
- lsid.split('=')])
- self.new_token(True)
- return True
- log.warning('unknown gmail error')
- raise Exception('unknown gmail error')
-
-
- def new_token(self, at = False):
- self.token_lock.__enter__()
-
- try:
- sid = self.sid
- lsid = self.lsid
- d = dict([
- sid.split('='),
- lsid.split('=')])
- self.getAuthToken(d, at)
- finally:
- pass
-
-
-
- def getAuthToken(self, d, at = False):
- d.update(service = 'mail')
- token = self.webrequest(self.baseAuthUrl + self.tokenUrl, **d)
- if not token:
- log.debug('Error getting authtoken. state is: %s', self.state)
- return None
-
- self.token = token.strip()
- if at:
- self.get_gmail_at()
- self.getAuthToken(d)
-
-
-
- def get_gmail_at(self):
- at_token = self.token
- url = self.internalBaseMailUrl + '?auth=%s' % at_token
- res = self.webrequest(url, follow_js_redirects = True)
-
- try:
- self.gmail_at
- except KeyError:
- log.debug('GMAIL_AT result: %r', res)
-
-
-
- def gmail_at(self):
- hosted = self.hosted
- at_path = None if hosted else '/mail'
- return self.jar._cookies['mail.google.com'][at_path]['GMAIL_AT'].value
-
- gmail_at = property(gmail_at)
-
- def update(self):
- log.info('update at %s', time.ctime(time.time()))
- EmailAccount.update(self)
- self.real_update(success = self.finish_update, error = self.on_error)
-
-
- def finish_update(self, updates):
- if updates is sentinel:
- log.warning('two updates were running at the same time')
- return None
-
-
- try:
- (updated_emails, updated_count) = updates
- except (TypeError, ValueError):
- log.error('Update failed for %s, assuming auth error', self.name)
- return None
-
- log.info('%s got %d new messages %s', self, updated_count, time.ctime(time.time()))
- self._received_emails(updated_emails[:25], updated_count)
-
-
- def real_update(self):
- if self.update_lock.acquire(False):
-
- try:
- if not self.token:
- info('no auth token yet, authenticating')
- if not self.authenticate():
- log.info('auth failed, returning None from real_update')
- return None
-
-
- info('updating Gmail account %s at %s' % (self.name, time.ctime(time.time())))
- (updated_emails, updated_count, _data) = parse_datapacks(self._get_notifier_data())
- updated_emails = chunks_to_emails(updated_emails)
- return (updated_emails, updated_count)
- finally:
- self.update_lock.release()
-
- else:
- return sentinel
-
- real_update = threaded(real_update)
-
- def webrequest(self, url, data = '', follow_js_redirects = False, **kwparams):
-
- try:
- response = self.http_opener.open(url, data + urlencode(kwparams.items()))
- resp = response.read()
- if follow_js_redirects:
- match = self.jsredirectMatcher.search(resp)
- if match:
- new_url = match.groups()[0]
- response = self.http_opener.open(self.baseAuthUrl + new_url)
- resp = response.read()
-
-
- return resp
- except (urllib2.HTTPError, urllib2.URLError):
- e = None
- if getattr(e, 'code', None) == 403:
- log.warning('Invalid username or password')
- self.bad_pw()
- return False
- else:
- print_exc()
- import sys
- print >>sys.stderr, 'url: %s' % url
- except Exception:
- e = None
- print_exc()
-
- return False
-
-
- from util import utf7_to_int as u7i
-
- def chunk_datapack(data):
- data = data[1:]
- (num, numbytes) = u7i(data)
- data = data[numbytes:]
- return (data[:num], data[num:])
-
-
- def get_chunk(data):
- (type_, numbytes) = u7i(data)
- data = data[numbytes:]
- if type_ == 184:
- (value, length_) = u7i(data)
- elif type_ == 152:
- (value, length_) = u7i(data)
- else:
- (length_, numbytes) = u7i(data)
- data = data[numbytes:]
- return (type_, data[:length_], data[length_:])
-
-
- def get_mid_date(data):
- orig_length = len(data)
- (length_, numbytes) = u7i(data)
- expected_length = orig_length - length_ - numbytes
- data = data[numbytes:]
- (msgid, numbytes) = u7i(data)
- data = data[numbytes:]
- (_unknown, numbytes) = u7i(data)
- data = data[numbytes:]
- (time_in_ms, numbytes) = u7i(data)
- data = data[numbytes:]
- return (msgid, time_in_ms, data)
-
- from collections import defaultdict
-
- def parse_chunk(chunk):
- retval = defaultdict(list)
- (mid, time_in_ms, data) = get_mid_date(chunk)
- retval['mid'] = mid
- retval['time'] = time_in_ms
- while data:
- (t, v, data) = get_chunk(data)
- if t == 146:
- v = parse_from(v)
- elif t == 184:
- v = u7i(v)[0]
-
- retval[t].append(v)
- return retval
-
-
- def chunks_to_emails(dictionaries):
- return [ dict_to_email(e) for e in dictionaries ]
-
-
- def parse_datapacks(data):
- retval = []
- while data[0] == '\n':
- (chunk, data) = chunk_datapack(data)
- retval.append(parse_chunk(chunk))
- num_messages = 0
- (type_, numbytes) = u7i(data)
- data = data[numbytes:]
- if type_ == 136:
- (num_messages, numbytes) = u7i(data)
- data = data[numbytes:]
-
- return (retval, num_messages, data)
-
-
- def parse_from(from_):
- retval = { }
- from_ = from_[1:]
- (retval['mystery_bytes1'], from_) = from_.split('\n', 1)
- (length_, numbytes) = u7i(from_)
- from_ = from_[numbytes:]
- retval['email_addr'] = from_[:length_]
- from_ = from_[length_:]
- (type_, numbytes) = u7i(from_)
- if type_ == 18:
- from_ = from_[numbytes:]
- (length_, numbytes) = u7i(from_)
- from_ = from_[numbytes:]
- retval['from_text'] = from_[:length_]
- from_ = from_[length_:]
-
- retval['remainder_bytes'] = from_
- return retval
-
-
- decode = lambda s: scrape_clean(s.decode('utf-8'))
-
- def dict_to_email(d):
- k = Storage(labels = 130, author = 146, subject = 162, snippet = 170, attachments = 178)
- msgid = d['mid']
- author_email = d[k.author][-1]['email_addr']
- author_name = decode(d[k.author][-1].get('from_text', ''))
- subject = decode(d[k.subject][-1])
- snippet = decode(d[k.snippet][-1])
- attachments = [ Storage(name = a) for a in d[k.attachments] ]
- labels = _[2]
- return Email(id = '%x' % msgid, fromname = author_name, fromemail = author_email, sendtime = datetime.fromtimestamp(d['time'] // 1000), subject = subject, content = snippet, attachments = attachments, labels = labels)
-
-